fix: preserve thinking block signatures and fix compaction headroom asymmetry#14393
fix: preserve thinking block signatures and fix compaction headroom asymmetry#14393gnadaban wants to merge 2 commits intoanomalyco:devfrom
Conversation
|
The following comment was made by an LLM, it may be inaccurate: Potential Related PRs Found:
These PRs address similar domains (thinking block signatures and compaction behavior), though they may be addressing different specific bugs or prior versions of the same issues. |
|
Re: related PRs flagged by bot Checked all three:
|
fd795c0 to
c045a8f
Compare
…rategy UI Root cause fix (from PR anomalyco#14393): - Always pass providerMetadata for reasoning parts (removed differentModel guard) - Always pass callProviderMetadata for tool parts - Fix asymmetric compaction buffer (use maxOutputTokens consistently) Configurable thinking strategy (none/strip/compact): - Settings > General: Thinking Strategy dropdown - Context tab: Always-visible strategy selector - Error card: Retry buttons for thinking block errors - Processor: Auto-compact on thinking error with compact strategy Default 'none' preserves original behavior.
c045a8f to
04021bb
Compare
b898bf0 to
cef2b52
Compare
cef2b52 to
a49278b
Compare
…rategy UI Root cause fix (from PR anomalyco#14393): - Always pass providerMetadata for reasoning parts (removed differentModel guard) - Always pass callProviderMetadata for tool parts - Fix asymmetric compaction buffer (use maxOutputTokens consistently) Configurable thinking strategy (none/strip/compact): - Settings > General: Thinking Strategy dropdown - Context tab: Always-visible strategy selector - Error card: Retry buttons for thinking block errors - Processor: Auto-compact on thinking error with compact strategy Default 'none' preserves original behavior.
0bf6a56 to
be50ae3
Compare
|
Confirming this bug is reproducible with Claude Opus 4.7 (released April 15, 2026) on Amazon Bedrock. Error appears at message 63: Environment:
The model works fine in AWS Console (fresh requests), but fails in OpenCode when replaying conversation history with cached thinking blocks. This PR's fix (removing the |
be50ae3 to
8f53ae2
Compare
|
Just rebased, there were hundreds of commits apparently on |
8f53ae2 to
bb23cf6
Compare
|
talking to someone on discord about this, not sure if it is you in discord but if not ill move discussion here. |
| } | ||
|
|
||
| if (msg.info.role === "assistant") { | ||
| const differentModel = `${model.providerID}/${model.id}` !== `${msg.info.providerID}/${msg.info.modelID}` |
There was a problem hiding this comment.
Killing this logic will break switching models mid convo for a variety of cases, we cannot do this, also your PR says compaction uses a different model? Well that'd only happen if you manually specify a different model and even then, this logic should prevent a separate model from causing issues
There was a problem hiding this comment.
Good point, what do you think of the revised change?
bb23cf6 to
626e8a5
Compare
c8af25d to
07ba2f7
Compare
…symmetry Two compounding bugs caused sessions to crash with 'thinking blocks cannot be modified' when compaction fired for models with extended thinking: 1. toModelMessages() stripped providerMetadata (including cryptographic signatures) from message parts when the current model differed from the original. Anthropic's API requires signatures to be byte-identical. Fix: always pass providerMetadata through — the API handles filtering. 2. isOverflow() used an asymmetric buffer when limit.input was set (capped at 20K via COMPACTION_BUFFER) vs the full maxOutputTokens on the non-input path. This caused compaction to trigger too late. Fix: use maxOutputTokens (capped at 32K) for both paths. Also fixed the non-input path to respect config.compaction.reserved.
07ba2f7 to
611ebdb
Compare
Issue for this PR
Closes #13286
Related: #10634, #8089, #12621, #8185
Type of change
What does this PR do?
Two compounding bugs cause sessions to crash with
'thinking' or 'redacted_thinking' blocks in the latest assistant message cannot be modifiedwhen compaction fires for models with extended thinking enabled (e.g. Claude Opus on Bedrock).Bug 1 — Thinking block signature stripping (
message-v2.ts)toModelMessages()compares the current model against each historical message's original model via adifferentModelguard. When they differ, allproviderMetadatais stripped from message parts. This removes the cryptographicsignaturethat Anthropic/Bedrock requires on thinking blocks, causing the API to reject the messages.The trigger is switching model variants mid-conversation within the same provider — e.g. changing from
claude-opus-4-6toclaude-opus-4-7on Bedrock, or any model mismatch between a message's recorded model and the current active model. When this happens, the Bedrock adapter receives areasoningTextblock without asignaturefield and rejects it withsignature: Field required.Note: in the default config (no custom compaction model), compaction uses the same providerID + modelID as the conversation, so
differentModeldoes not fire during compaction. The bug manifests when switching model variants mid-conversation.The fix narrows the guard from
differentModel(providerID + modelID) todifferentProvider(providerID only). Provider metadata is namespaced (e.g.{ bedrock: { signature: "..." } }), so passing it to a different model variant within the same provider is always safe. Stripping is still applied when crossing provider boundaries (e.g. Bedrock → OpenAI) to avoid leaking provider A's metadata to provider B.Bug 2 — Compaction headroom asymmetry (
overflow.ts)isOverflow()had an asymmetric buffer calculation:limit.input:reserved = Math.min(20_000, maxOutputTokens)→ only 20K headroomlimit.input:reserved = maxOutputTokens→ full 32K headroomThis meant models with
limit.inputcould grow ~12K tokens larger before compaction triggered, making context overflow more likely.The fix removes the 20K cap and uses
maxOutputTokens()(itself capped at 32K viaOUTPUT_TOKEN_MAX) for both paths. Also fixed the non-input path to respectconfig.compaction.reserved— previously it hardcodedmaxOutputTokens(), ignoring the user's configured override from #12924.How did you verify your code works?
Screenshots / recordings
N/A — not a UI change.
Checklist